﻿//-----------------------------------------------------------------------
// <copyright file="SmartTagEventReceiver.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation.
// All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
// </copyright>
// <author>Medha</author>
// <date>16-May-2011</date>
//-----------------------------------------------------------------------

namespace SmartTag.EventReceivers
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Taxonomy;
    using SmartTag.Common.IFilter;
    using SmartTag.Common.Taxonomy;
    using SmartTag.Common.Utility;
    using SmartTag.Configuration;

    /// <summary>
    /// List Item Events
    /// </summary>
    public class SmartTagEventReceiver : SPItemEventReceiver
    {
        /// <summary>
        /// Asynchronous After event that occurs after a new item has been added to its containing object.
        /// </summary>
        /// <param name="properties">SPListItem Properties</param>
        public override void ItemAdded(SPItemEventProperties properties)
        {
            try
            {
                DocumentLibraryConfiguration configuration = ConfigurationHelper.LoadConfiguration(properties.List);
                if (configuration != null && configuration.SmartTagEnabled)
                {
                    List<ColumnConfiguration> metadatacolumns = configuration.ColumnConfiguration;
                    if (metadatacolumns != null && metadatacolumns.Count > 0)
                    {
                        this.GetManagedMetadata(properties.ListItem, configuration.ColumnConfiguration);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Error occured in ItemAdded", (int)TraceLogEventId.ItemAdded);
            }

            base.ItemAdded(properties);
        }

        /// <summary>
        /// Gets the managed metadata. 
        /// </summary>
        /// <param name="item">The listitem.</param>
        /// <param name="metadatacolumns">The metadatacolumns.</param>
        private void GetManagedMetadata(SPListItem item, List<ColumnConfiguration> metadatacolumns)
        {
            try
            {
                // Check if item has a file
                if (item.File != null)
                {
                    using (FilterWrapper filter = new FilterWrapper(Path.GetExtension(item.File.Name)))
                    {
                        using (Stream stream = item.File.OpenBinaryStream())
                        {
                            filter.InitializeFromStream(stream);
                            using (FilterStreamReader reader = new FilterStreamReader(filter))
                            {
                                // Get the maximum word count for list
                                int wordCount = this.GetMaxWordCount(metadatacolumns);

                                string contents = reader.ReadWords(wordCount);

                                if (!string.IsNullOrEmpty(contents))
                                {
                                    foreach (ColumnConfiguration columnConfig in metadatacolumns)
                                    {
                                        TaxonomyField field = item.Fields[new Guid(columnConfig.ColumnId)] as TaxonomyField;
                                        List<Term> terms = new List<Term>();
                                        terms = TaxonomyHelper.LoadTerms(field);
                                        string contentsToScan = contents;

                                        // Check if the word count is same
                                        if (wordCount == columnConfig.WordsToScan)
                                        {
                                            contentsToScan = contents;
                                        }
                                        else
                                        {
                                            contentsToScan = this.GetWords(contents, columnConfig.WordsToScan);
                                        }

                                        if (terms.Count > 0)
                                        {
                                            Tagger.Tag(item, terms, field, contentsToScan, columnConfig.Relevance);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                item.SystemUpdate(false);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Error occured in GetManagedMetadata", (int)TraceLogEventId.GetManagedMetadata);
            }
        }

        /// <summary>
        /// Find the maximum number of words that we have to read from document
        /// </summary>
        /// <param name="columnConfig">The column config.</param>
        /// <returns>Max no. of Words to be scanned</returns>
        private int GetMaxWordCount(List<ColumnConfiguration> columnConfig)
        {
            int maxCount = 0;

            foreach (ColumnConfiguration config in columnConfig)
            {
                if (config.WordsToScan > maxCount)
                {
                    maxCount = config.WordsToScan;
                }
            }

            return maxCount;
        }

        /// <summary>
        /// Get the number of words from given string
        /// </summary>
        /// <param name="contents">The string contents.</param>
        /// <param name="count">The word count.</param>
        /// <returns>Contents To Scan</returns>
        private string GetWords(string contents, int count)
        {
            try
            {
                int words = count;

                for (int i = 0; i < contents.Length; i++)
                {
                    if (contents[i] == ' ')
                    {
                        words--;
                    }

                    if (words == 0)
                    {
                        return contents.Substring(0, i);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Error occured in GetWords", (int)TraceLogEventId.GetManagedMetadata);
            }

            return string.Empty;
        }
    }
}
